package phototagger.imgsim;

import java.awt.image.BufferedImage;
import java.awt.image.DirectColorModel;
import java.awt.image.AffineTransformOp;
import java.awt.geom.AffineTransform;

/** This is a class for methods that convert BufferedImage objects to YIQImage objects **/
public class Converter {

    public static final boolean DEBUG  = false;

    public static final int BITS       = 32;
    public static final int RED_MASK   = 0xff0000;
    public static final int BLUE_MASK  = 0x00ff00;
    public static final int GREEN_MASK = 0x0000ff;
    public static final int ALPHA_MASK = 0xff00000;

    private double[][] Yelements = 
	new double[YIQImage.SCALED_IMAGE_WIDTH][YIQImage.SCALED_IMAGE_HEIGHT]; 
    private double[][] Ielements =
	new double[YIQImage.SCALED_IMAGE_WIDTH][YIQImage.SCALED_IMAGE_HEIGHT]; 
    private double[][] Qelements =
	new double[YIQImage.SCALED_IMAGE_WIDTH][YIQImage.SCALED_IMAGE_HEIGHT];


    public Converter(BufferedImage image, String colorspace)
	throws Exception {
	if (!colorspace.equals(YIQImage.COLORSPACE)) {
	    String m = "Luke is lazy and dumb...";
	    throw new IllegalArgumentException(m);
	}

		BufferedImage scaled = scale(image);
		convertToYiq(scaled);
    }


    /** Affine transform rescale **/
    public BufferedImage scale(BufferedImage image) throws Exception {
	double xscale;
	double yscale;	
	xscale = (double)YIQImage.SCALED_IMAGE_WIDTH / (double)image.getWidth();
	yscale = (double)YIQImage.SCALED_IMAGE_HEIGHT / (double)image.getHeight();
	AffineTransformOp op = new 
	    AffineTransformOp(AffineTransform.getScaleInstance(xscale, yscale),
			      null);	
	return op.filter(image, null); 
    }

    /** given an (RGB) BufferedImage this will set the Yelements,
	Ielements, and Qelements arrays with converted YIQ values.
	TODO: make a utility class that does the conversions from
	BufferedImage to YIQ or RGB or whatever. Refactor this out.
    **/
    public void convertToYiq(BufferedImage image) 
	throws Exception {

	int width  = image.getWidth();
	int height = image.getHeight();
	int RGBpixel;
	
	// Commented out to let people search for their company logos!
	// uncommented out because this should've already been scaled to
	// 128 x 128.
	
	if((width < YIQImage.SCALED_IMAGE_WIDTH) ||
	   (height < YIQImage.SCALED_IMAGE_HEIGHT)) {
	    String m = "Sorry, your image was too small. It was " + width +
		"x" + height + " but it needs to be at least " +
		YIQImage.SCALED_IMAGE_WIDTH + "x" + YIQImage.SCALED_IMAGE_HEIGHT;
	    throw new Exception(m);
	}

	for(int x=0; x<width; x++) {
	    for(int y=0; y<height; y++) {
		// get that pixel
		RGBpixel = image.getRGB(x, y);
		rgbPixelToYiq(RGBpixel, x, y);
	    }
	}
    }

    
    /** Converts a RGBpixel of TYPE_INT_RGBA into the equivalent
	Y, I, and Q values and adds them to the YIQImage
	@param RGBpixel the RGB pixel to be converted
	@param x the x location of the pixel being converted
	@param y the y location of the pixel being converted
    **/
    public void rgbPixelToYiq(int RGBpixel, int x, int y) {

	//TODO: use the DirectColorModel.getRGBDefault -- they're the same
	// but test it first god damnit!
	DirectColorModel dcm = 
	    new DirectColorModel(BITS, RED_MASK, BLUE_MASK, GREEN_MASK,
				 ALPHA_MASK);
	
	int red   = dcm.getRed(RGBpixel);
	int green = dcm.getGreen(RGBpixel);
	int blue  = dcm.getBlue(RGBpixel);

	// TODO: make these constants ... but I can't think of any good names
	double Y = ((0.299d * red) +
		    (0.587d * green) + (0.114d * blue)) / 256;
	double I = ((0.596d * red) -
		    (0.274d * green) - (0.322d * blue)) / 256;
	double Q = ((0.212d * red) -
		    (0.523d * green) + (0.311d * blue)) / 256;

	if(DEBUG) {
	    String m = "Setting pixel ("+x+","+y+") to Y="+Y+",Q="+Q+",I="+I;
	    System.out.println(m);
	}
	
	setYiqPixel(Y, I, Q, x, y);
    }
    
    /** setPixel actually does the work of putting the YIQ triplet into
	the appropriate places in the arrays contained by a YIQImage.
	
	<p>Sorry about the confusing parameter names...
	@param Y Y colorspace value
	@param I I colorspace value
	@param Q Q colorspace value
	@param x x position of the pixel
	@param y y position of the pixel
    **/
    private void setYiqPixel(double Y, double I, double Q, int x, int y) {
	if(DEBUG) {
	    String m = "In setPixel. Setting ("+x+","+y+") to Y="+Y+",Q="+Q+
		",I="+I;
	    System.out.println(m);
	}

	Yelements[y][x] = Y;
	Ielements[y][x] = I;
	Qelements[y][x] = Q;
    }

    public double[][] getElements(char color) {
	switch(color) {
	case 'Y':
	    return Yelements;
	case 'I':
	    return Ielements;
	case 'Q':
	    return Qelements;
	default : return null;
	}
    }
}
